﻿using System.Windows.Forms;
using System.Drawing;

namespace ToolUtil
{
    public static class TreeViewHandler
    {
        public const string STATE_CHECK = "1";
        public const string STATE_UNCHECK = "2";
        public const string STATE_PARTCHECK = "3";
        public const string STATE_NOUSEUNCHECK = "4";

        /// <summary>
        /// 当要勾一个节点时，需要做的联动处理
        /// </summary>
        /// <param name="tn"></param>
        public static void checkNode(TreeNode tn)
        {
            if (tn.ForeColor != Color.Gray)
            {
                #region 考虑本级
                if (tn.ForeColor != Color.Gray)//自己不是禁用状态
                {
                    setSonNodeInCheck(tn);
                }
                #endregion 结束 考虑本级

                #region 考虑下级

                #endregion 结束 考虑下级

                #region 考虑上级
                SetFatherNodeInCheck(tn);

                #endregion 结束 考虑上级
            }
        }
        public static void unCheckNode(TreeNode tn)
        {
            if (tn.ForeColor != Color.Gray)
            {
                #region 考虑本级和下级
                //l/tn.ToolTipText = "2";
                setNodeState(tn, STATE_UNCHECK);
                SetSonNodeInUncheck(tn);

                #endregion 结束 考虑本级和下级

                #region 考虑上级

                SetFatherNodeInUncheck(tn);

                #endregion 结束 考虑上级
            }
        }

        ////////////////////
        //设置节点选定状态：规则.1：用于当节点被勾除时,检查是否有子节点，需清除所有子节点的选定状态；
        public static void SetSonNodeInUncheck(TreeNode tn)
        {
            foreach (TreeNode t in tn.Nodes)
            {

                setNodeState(t, STATE_UNCHECK);
                if (t.Nodes.Count != 0)
                {
                    SetSonNodeInUncheck(t);
                }
            }
        }


        //设置节点选定状态：规则.2：用于当节点被勾除时,检查是否有父节点，如有，则根据兄弟节点的选定状态修改父节点的选定状态
        public static void SetFatherNodeInUncheck(TreeNode tn)
        {

            if (tn.Parent == null)
                return;
            int checkNum = 0;
            int unCheckNum = 0;
            int partChekNum = 0;
            //统计兄弟节点中选中情况
            foreach (TreeNode t in tn.Parent.Nodes)
            {
                if (t.ToolTipText.Equals("1"))
                    checkNum++;
                if (t.ToolTipText.Equals("2"))
                    unCheckNum++;
                if (t.ToolTipText.Equals("3"))
                    partChekNum++;
            }

            if (checkNum == 0 && partChekNum == 0)//如果兄弟均无一勾选
            {
                if (tn.Parent.ForeColor != Color.Gray)
                {
                    setNodeState(tn.Parent, STATE_UNCHECK);
                }
            }
            else//兄弟部分勾选了
            {
                if (tn.Parent.ForeColor != Color.Gray)
                {
                    setNodeState(tn.Parent, STATE_PARTCHECK);
                }
            }
            //递归
            SetFatherNodeInUncheck(tn.Parent);

        }


        //设置节点选定状态：规则.1：当节点被勾选时，设置所有子节点勾选（强制）!
        public static void SetAllSonNodeCheck(TreeNode tn)
        {

            foreach (TreeNode t in tn.Nodes)
            {
                setNodeState(t, STATE_CHECK);
                if (t.Nodes.Count != 0)
                {
                    SetAllSonNodeCheck(t);
                }
            }

        }


        //设置节点选定状态：规则.2：当节点被勾选时，检查是否有父节点，如有，则根据兄弟节点的选定状态修改父节点的选定状态
        public static void SetFatherNodeInCheck(TreeNode tn)
        {

            if (tn.Parent == null)
                return;
            if (tn.ToolTipText.Equals("3"))//如果我自己为部分勾
            {
                setNodeState(tn.Parent, STATE_PARTCHECK);
            }
            else
            {
                int checkNum = 0;
                int unCheckNum = 0;
                int partChekNum = 0;
                int noUseUnCheckNum = 0;
                //统计兄弟节点中选中情况
                foreach (TreeNode t in tn.Parent.Nodes)
                {
                    if (t.ToolTipText.Equals("1"))
                        checkNum++;
                    if (t.ToolTipText.Equals("2"))
                        unCheckNum++;
                    if (t.ToolTipText.Equals("3"))
                        partChekNum++;
                    if (t.ToolTipText.Equals(""))
                        noUseUnCheckNum++;
                }
                //如果兄弟节点中没有一个是未选中的和部分选中的，即全选
                if (unCheckNum == 0 && partChekNum == 0 && noUseUnCheckNum == 0)
                {

                    setNodeState(tn.Parent, STATE_CHECK);
                }
                else //那就说明有部分是没勾上
                {
                    setNodeState(tn.Parent, STATE_PARTCHECK);
                }
            }
            SetFatherNodeInCheck(tn.Parent);
        }

        /// <summary>
        /// 判断指定节点的所有子节点有无禁用节点
        /// </summary>
        /// <param name="tn"></param>
        /// <returns></returns>
        public static bool isHaveNoUseSonNode(TreeNode tn)
        {
            bool result = false;
            foreach (TreeNode item in tn.Nodes)
            {
                if (item.ForeColor == Color.Gray)
                {
                    return true;
                }
                else
                {
                    if (item.Nodes.Count > 0)
                    {
                        if (isHaveNoUseSonNode(item))
                        {
                            return true;
                        }
                    }
                }

            }
            return result;
        }

        public static bool setSonNodeInCheck(TreeNode tn)
        {
            bool isHaveNoUseAndPartSonNode = false;//是否有禁用的字集 或 部分选择的字集
            foreach (TreeNode t in tn.Nodes)
            {
                if (t.ForeColor != Color.Gray)
                {
                    setNodeState(t, STATE_CHECK);
                    if (t.Nodes.Count > 0)
                    {
                        if (!isHaveNoUseAndPartSonNode)
                        {
                            isHaveNoUseAndPartSonNode = setSonNodeInCheck(t); //如果已经是存在有禁用或部分选中字集了，就不要再判断了，避免弄脏数据。
                        }
                        else
                        {
                            setSonNodeInCheck(t);
                        }
                    }
                    if (t.ToolTipText.Equals("3"))//若果t在设置完后变成部分选中状态
                    {
                        isHaveNoUseAndPartSonNode = true;
                    }
                }
                else
                {
                    isHaveNoUseAndPartSonNode = true;
                }
            }
            if (isHaveNoUseAndPartSonNode)
            {
                setNodeState(tn, STATE_PARTCHECK);
            }
            else
            {
                setNodeState(tn, STATE_CHECK);
            }
            return isHaveNoUseAndPartSonNode;
        }



        public static void setNodeState(TreeNode tn, string state)
        {
            tn.ToolTipText = state;
            switch (state)
            {
                case STATE_CHECK:
                    tn.Checked = false;
                    tn.Checked = true;
                    break;
                case STATE_UNCHECK:
                    tn.Checked = true;
                    tn.Checked = false;
                    break;
                case STATE_PARTCHECK:
                    tn.Checked = false;
                    tn.Checked = true;
                    break;
                case STATE_NOUSEUNCHECK:
                    tn.ForeColor = Color.Gray;
                    break;

                default:
                    break;
            }
        }
    }
}
